<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<style>
 :root {
   background-color: #333333;
 }
</style>
<body>
  <script>
    function caidai () {
      let imgElList = [];
      let imgLoadCount = 0;
      let raf = true;
      let myCanvas;
      let _createClass = (function () {
        function defineProperties (target, props) {
          for (let i = 0; i < props.length; i++) {
            let descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) {
              descriptor.writable = true;
            } Object.defineProperty(target, descriptor.key, descriptor);
          }
        } return function (Constructor, protoProps, staticProps) {
          if (protoProps) {
            defineProperties(Constructor.prototype, protoProps);
          } if (staticProps) {
            defineProperties(Constructor, staticProps);
          }return Constructor;
        };
      })();
      // eslint-disable-next-line
      function _classCallCheck (instance, Constructor) {
        if (!(instance instanceof Constructor)) {
          throw new TypeError('Cannot call a class as a function');
        }
      }

      let Progress = (function () {
        function Progress () {
          // eslint-disable-next-line
          let param = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];

          _classCallCheck(this, Progress);

          this.timestamp = null;
          this.duration = param.duration || Progress.CONST.DURATION;
          this.progress = 0;
          this.delta = 0;
          this.progress = 0;
          this.isLoop = Boolean(param.isLoop);

          this.reset();
        }

        Progress.prototype.reset = function reset () {
          this.timestamp = null;
        };

        Progress.prototype.start = function start (now) {
          this.timestamp = now;
        };

        Progress.prototype.tick = function tick (now) {
          if (this.timestamp) {
            this.delta = now - this.timestamp;
            this.progress = Math.min(this.delta / this.duration, 1);
            if (this.progress >= 1) {
              raf = false;
              try {
                if (myCanvas) {
                  myCanvas.remove();
                }
              } catch (error) {
                console.log(error);
              }
            }
            return this.progress;
          }
          return 0;
        };

        _createClass(Progress, null, [
          {
            key: 'CONST',
            get: function get () {
              return {
                DURATION: 1000,
              };
            },
          },
        ]);

        return Progress;
      })();

      let Confetti = (function () {
        function Confetti (param) {
          _classCallCheck(this, Confetti);

          this.parent = param.elm || document.body;
          this.canvas = document.createElement('canvas');
          myCanvas = this.canvas;
          this.canvas.setAttribute('class', 'canvas_caidai');
          this.ctx = this.canvas.getContext('2d');
          this.width = param.width || this.parent.offsetWidth;
          this.height = param.height || this.parent.offsetHeight;
          this.length = param.length || Confetti.CONST.PAPER_LENGTH;
          this.yRange = param.yRange || this.height;
          this.progress = new Progress({
            duration: param.duration,
            isLoop: false,
          });
          this.rotationRange = typeof param.rotationLength === 'number' ? param.rotationRange : 10;
          this.speedRange = typeof param.speedRange === 'number' ? param.speedRange : 10;
          this.sprites = [];

          this.canvas.style.cssText = ['display: block', 'position: absolute', 'top: 0', 'left: 0', 'pointer-events: none'].join(';');

          this.render = this.render.bind(this);
          this.build();

          document.querySelector('body').append(this.canvas);
          this.progress.start(performance.now());
          if (raf) {
            requestAnimationFrame(this.render);
          }
        }

        Confetti.prototype.build = function build () {
          for (let i = 0; i < this.length; ++i) {
            let canvas = document.createElement('canvas'),
              ctx = canvas.getContext('2d');

            canvas.width = Confetti.CONST.SPRITE_WIDTH;
            canvas.height = Confetti.CONST.SPRITE_HEIGHT;

            canvas.position = {
              initX: Math.random() * this.width,
              initY: -canvas.height - Math.random() * this.yRange,
            };

            canvas.rotation = this.rotationRange / 2 - Math.random() * this.rotationRange;
            canvas.speed = this.speedRange / 2 + Math.random() * (this.speedRange / 2);

            // ctx.save();
            // ctx.fillStyle = Confetti.CONST.COLORS[Math.random() * Confetti.CONST.COLORS.length | 0];
            // ctx.fillRect(0, 0, canvas.width, canvas.height);
            // eslint-disable-next-line
            ctx.drawImage(Confetti.CONST.IMGS[Math.random() * Confetti.CONST.IMGS.length | 0], 0, 0, canvas.width, canvas.height);
            ctx.restore();

            this.sprites.push(canvas);
          }
        };

        Confetti.prototype.render = function render (now) {
          let progress = this.progress.tick(now);
          this.canvas.width = this.width;
          this.canvas.height = this.height;
          for (let i = 0; i < this.length; ++i) {
            this.ctx.save();
            // eslint-disable-next-line
            this.ctx.translate(this.sprites[i].position.initX + this.sprites[i].rotation * Confetti.CONST.ROTATION_RATE * progress, this.sprites[i].position.initY + progress * (this.height + this.yRange));
            this.ctx.rotate(this.sprites[i].rotation);
            // eslint-disable-next-line
            this.ctx.drawImage(this.sprites[i], -Confetti.CONST.SPRITE_WIDTH * Math.abs(Math.sin(progress * Math.PI * 2 * this.sprites[i].speed)) / 2, -Confetti.CONST.SPRITE_HEIGHT / 2, Confetti.CONST.SPRITE_WIDTH * Math.abs(Math.sin(progress * Math.PI * 2 * this.sprites[i].speed)), Confetti.CONST.SPRITE_HEIGHT);
            this.ctx.restore();
          }
          if (raf) {
            requestAnimationFrame(this.render);
          }
        };

        _createClass(Confetti, null, [
          {
            key: 'CONST',
            get: function get () {
              return {
                SPRITE_WIDTH: 9,
                SPRITE_HEIGHT: 16,
                PAPER_LENGTH: 100,
                DURATION: 8000,
                ROTATION_RATE: 50,
                COLORS: ['#EF5350', '#EC407A', '#AB47BC', '#7E57C2', '#5C6BC0', '#42A5F5', '#29B6F6', '#26C6DA', '#26A69A', '#66BB6A', '#9CCC65', '#D4E157', '#FFEE58', '#FFCA28', '#FFA726', '#FF7043', '#8D6E63', '#BDBDBD', '#78909C'],
                IMGS: imgElList,
              };
            },
          },
        ]);

        return Confetti;
      })();
      // eslint-disable-next-line
      this.go = function () {
        raf = true;
        imgLoadCount = 0;
        imgElList = [];
        let DURATION = 4000,
          LENGTH = 60;
        let imgs = [
          'http://localhost:8080/canvas-confetti/icon/caidai1@2x.png',
          'http://localhost:8080/canvas-confetti/icon/caidai2@2x.png',
          'http://localhost:8080/canvas-confetti/icon/caidai3@2x.png',
          'http://localhost:8080/canvas-confetti/icon/caidai4@2x.png',
          'http://localhost:8080/canvas-confetti/icon/caidai5@2x.png',
          'http://localhost:8080/canvas-confetti/icon/caidai6@2x.png',
        ];
        for (let i = 0; i < 6; i++) {
          let img = new Image();
          img.src = imgs[i];
          imgElList.push(img);
          // eslint-disable-next-line
          img.onload = function () {
            imgLoadCount++;
            if (imgLoadCount === imgs.length) {
              raf = true;
              // eslint-disable-next-line
              new Confetti({
                width: window.innerWidth,
                height: window.innerHeight,
                length: LENGTH,
                duration: DURATION,
              });
            }
          };
        }
      };
    }
    new caidai().go();
  </script>
</body>
</html>